#include "jansson.h"
#include <UIJSONParser.h>
#include "CommonUtil.h"

json_t* getValue(json_t *node, std::list<std::string> keys)
{
	if (keys.size() == 0 || node == NULL || !json_is_object(node))
		return NULL;

	json_t * objectNode;
	std::string curKey = keys.front();

	size_t bIndex = curKey.find("[");
	if ( bIndex == std::string::npos ) // typical variable
	{
		objectNode = json_object_get(node, curKey.c_str());
	}
	else // item of an array
	{
		std::string mainKey = curKey.substr(0, bIndex);
		json_t * arrayNode = json_object_get(node, mainKey.c_str());
		if (!json_is_array(arrayNode)) {
			free(node);
			free(arrayNode);
			return NULL;
		}

		size_t eIndex = curKey.find("]");
		if (eIndex == std::string::npos) {
			free(node);
			free(arrayNode);
			return NULL;
		}
		
		std::string strIndex = curKey.substr(bIndex+1, eIndex-bIndex-1);
		int index = atoi(strIndex.c_str());
		if (index < 0 || index >= (int)json_array_size(arrayNode)) {
			free(node);
			free(arrayNode);
			return NULL;
		}
		objectNode = json_array_get(arrayNode, index);
	}
	
	keys.pop_front();

	free(node);
	if (keys.size() == 0) 
		return objectNode;
	else
		return getValue(objectNode, keys);
}

bool UIJSONParser::getString(std::string jsonString, std::string key, std::string &value) 
{
	json_error_t * json_error	= new json_error_t();
	json_t * root = json_loads(jsonString.c_str(), JSON_DECODE_ANY, json_error);
	if (root == NULL)
		return false;

	std::list<std::string> keys;
	splitKey(key, keys);

	json_t * object = getValue(root, keys);
	if (object == NULL)
		return false;

	if (!json_is_string(object)) {
		free(object);
		return false;
	}

	value = json_string_value(object);
	free(object);
	return true;
}

bool UIJSONParser::getInt(std::string jsonString, std::string key, int& value) 
{
	json_error_t * json_error	= new json_error_t();
	json_t * root = json_loads(jsonString.c_str(), JSON_DECODE_ANY, json_error);
	if (root == NULL)
		return false;

	std::list<std::string> keys;
	splitKey(key, keys);

	json_t * object = getValue(root, keys);
	if (object == NULL)
		return false;

	if (!json_is_integer(object)) {
		free(object);
		return false;
	}

	value = json_integer_value(object);
	free(object);
	return true;
}

bool UIJSONParser::getBool(std::string jsonString, std::string key, bool& value)
{
	json_error_t * json_error	= new json_error_t();
	json_t * root = json_loads(jsonString.c_str(), JSON_DECODE_ANY, json_error);
	if (root == NULL)
		return false;

	std::list<std::string> keys;
	splitKey(key, keys);

	json_t * object = getValue(root, keys);
	if (object == NULL)
		return false;

	if (!json_is_boolean(object)) {
		free(object);
		return false;
	}

	value = (json_is_true(object));
	return true;
}

bool UIJSONParser::getDouble(std::string jsonString, std::string key, double& value) 
{
	json_error_t * json_error	= new json_error_t();
	json_t * root = json_loads(jsonString.c_str(), JSON_DECODE_ANY, json_error);
	if (root == NULL)
		return false;

	std::list<std::string> keys;
	splitKey(key, keys);

	json_t * object = getValue(root, keys);
	if (object == NULL)
		return false;

	if(!json_is_real(object)) {
		free(object);
		return false;
	}

	value = json_real_value(object);
	free(object);
	return true;
}

bool UIJSONParser::getObject(std::string jsonString, std::string key, std::string &value) 
{
	json_error_t * json_error	= new json_error_t();
	json_t * root = json_loads(jsonString.c_str(), JSON_DECODE_ANY, json_error);
	if (root == NULL)
		return false;

	std::list<std::string> keys;
	splitKey(key, keys);

	json_t * object = getValue(root, keys);
	if (object == NULL)
		return false;

	if (json_is_object(object)) {
		char* objectValue = json_dumps(object, 0);
		value.assign(objectValue);
		free(objectValue);
	}
	else if (json_is_array(object)) {
		
	}
	else if (json_is_string(object)) {
		value.assign(json_string_value(object));
	}
	else if (json_is_integer(object)) {
		int v = json_integer_value(object);
		value.assign(toStr(v));
	}
	else if (json_is_real(object)) {
		double v = json_real_value(object);
		value.assign(toStr(v));
	}
	else if (json_is_true(object)) {
		value.assign("true");
	}
	else if (json_is_false(object)) {
		value.assign("false");
	}
	else {
		free(object);
		return false;
	}
	free(object);
	return true;
}

int UIJSONParser::getArraySize(std::string jsonString, std::string key)
{
	json_error_t * json_error	= new json_error_t();
	json_t * root = json_loads(jsonString.c_str(), JSON_DECODE_ANY, json_error);
	if (root == NULL)
		return -1;

	std::list<std::string> keys;
	splitKey(key, keys);

	json_t * object = getValue(root, keys);
	if (object == NULL)
		return -1;

	if(!json_is_array(object)) {
		free(object);
		return -1;
	}
	
	int size = json_array_size(object);
	free(object);
	return size;
}

void UIJSONParser::splitKey(std::string key, std::list<std::string>& keys)
{
	std::string splitter = ".";
	int i, slen = splitter.length();
	i = (int)key.find(splitter);
	while(i>=0) {
		keys.push_back(key.substr(0,i));
		key = key.substr(i+slen, key.length()-i-slen);
		i = (int)key.find(splitter);
	}
	keys.push_back(key);
}